/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package A1;

/**
 *
 * @author Mary Llenos
 * MainUI class is the user interface for the traffic simulation.  It contains
 * the menu and how to control or perform each menu.
 */
public class MainUI {

    private ProjModel pm;
    private Grid cell;
    private Car horCarArray[];
    private Car verCarArray[];
    private boolean start; // when false, no Grid has been set yet
    private int tcounter; // counter for traffic light signal
    private int hcounter; // horCarArray element
    private int vcounter; // verCarArray element
    private int simHCycle; // counter for simulation cycle for horizontal street
    private int simVCycle; // counter for simulation cycle for vertical street
    private int nextHCar; // when nextHCar is equal to simHCycle, new car will enter in h street
    private int nextVCar; // when nextVCar is equal to simHCycle, new car will enter in v street
    private int hInc; // hInc increments nextHCar which is equal to probability of car in horizontal street
    private int vInc; // vInc increments nextVCar which is equal to probability of car in vertical street
    private boolean hReset; // if hReset is true, the loop will equal to size
    private boolean vReset; // if vReset is true, the loop will equal to size
    private final int SIZE;  //constant variable for declaring the Array

    /**
     * Default constructor of MainUI for initializing instance variables and
     * instantiate new objects
     */
    public MainUI() {
        pm = new ProjModel();
        start = false;
        tcounter = 1;
        hcounter = 0;
        vcounter = 0;
        nextHCar = 0;
        nextVCar = 0;
        hInc = 0;
        vInc = 0;
        hReset = false;
        vReset = false;
        SIZE = 100;
    }

    /**
     * Prints out on the screen the menu and accepts user input.
     */
    public void showMenu() {

        boolean exit = false;
        int sim = 0;
       
        horCarArray = new Car[SIZE];
        verCarArray = new Car[SIZE];
        /*
        === MENU ===
        1. Set Number of horizontal lanes (H-street) [min 1, max 3]
        2. Set Number of vertical lanes  (V-street) [min 1, max 4]
        3. Set Probability of a car entering H-street [min 0, max 1]
        3. Set Probability of a car entering V-street [min 0, max 1]
        5. Run one simulation cycle
        6. Set and run number of simulation cycles [min 1, max 10]
        Enter your choice>           */
        System.out.print( " === MENU ===\n" +
                "1. Set Number of horizontal lanes (H-street) [min 1, max 3]\n" +
                "2. Set Number of vertical lanes  (V-street) [min 1, max 4]\n" +
                "3. Set Probability of a car entering H-street [min 0, max 1]\n" +
                "4. Set Probability of a car entering V-street [min 0, max 1]\n" +
                "5. Run one simulation cycle\n" +
                "6. Set and run number of simulation cycles [min 1, max 10]\n" +
                "7. Exit\n");
        do {
            String userChoice = GetUserInput.getUserChoice("Please enter your menu choice>");
            int userChoiceInt = Integer.parseInt(userChoice);

            switch(userChoiceInt) {
                case 1 : System.out.println("Menu 1");
                         setNumHorLanes();
                         hcounter = 0;
                         start = false;
                    break;
                case 2 : System.out.println("Menu 2");
                         setNumVerLanes();
                         hcounter = 0;
                         start = false;
                    break;
                case 3 : System.out.println("Menu 3");
                         setProbHorLaneCar();

                    break;
                case 4 : System.out.println("Menu 4");
                         setProbVerLaneCar();
                    break;
                case 5 : System.out.println("Menu 5");
                         runSim(sim, showProbCarHLane(),showProbCarVLane());
                         sim = 1;
                         start = true;
                    break;
                case 6 : System.out.println("Menu 6");
                         String cycle = GetUserInput.getUserChoice("Enter no of Cycle>");
                         int noOfCycle = Integer.parseInt(cycle);
                         runSim(noOfCycle, showProbCarHLane(),showProbCarVLane());
                         sim = 1;
                    break;
                case 7 : exit = true;
                    break;
                default : System.out.println("Error in entering menu choice");
                    break;
            }
        } while (exit != true);
    }

    /**
     * Asks and accept user input to set the number of horizontal lane
     */
    public void setNumHorLanes () {
        boolean choice = false;
        int lowerLimit = 1;
        int upperLimit = 3;
        do {
            String userChoice = GetUserInput.getUserChoice("Enter number of horiz lanes : ");
            int userChoiceInt = Integer.parseInt(userChoice);
            if (userChoiceInt > upperLimit || userChoiceInt < lowerLimit) {
               System.out.println("Error in entering horiz lanes");
               System.out.println("Please enter number from 1 to 3. ");
            }
            else { //if user enter the correct input
                pm.setHorLanes(userChoiceInt);
                //let user set the number
                choice = true;
            }
        }while(choice != true);
    }

    /**
     * Asks and accept user input to set the number of vertical lane
     */
    public void setNumVerLanes () {
        boolean choice = false;
        int lowerLimit = 1;
        int upperLimit = 4;
        do {
            String userChoice = GetUserInput.getUserChoice("Enter number of vert lanes : ");
            int userChoiceInt = Integer.parseInt(userChoice);
            if (userChoiceInt > upperLimit || userChoiceInt < lowerLimit) {
               System.out.println("Error in entering vert lanes");
               System.out.println("Please enter number from 1 to 4. ");
            }
            else { //if user enter the correct input
                pm.setVerLanes(userChoiceInt);
                //let user set the number
                choice = true;
            }
        }while (choice != true);
    }

    /**
     * Asks and accept user input to set the probability of car entering
     * in the horizontal street
     */
    public void setProbHorLaneCar(){
        boolean choice = false;
        int lowerLimit = 0;
        int upperLimit = 1;
        do {
            String userChoice = GetUserInput.getUserChoice("Enter number of probable cars in H-Lane : ");
            double userChoiceInt = Double.valueOf(userChoice.trim()).doubleValue();

            if (userChoiceInt > upperLimit || userChoiceInt < lowerLimit) {
               System.out.println("Error in entering probable number");
               System.out.println("Please enter number either 0 or 1. ");
            }
            else { //if user enter the correct input
                pm.setProbCarHLane(userChoiceInt);
                //let user set the number
                choice = true;
            }
        }while (choice != true);
        simHCycle = 1;
        double prob = 1.0/showProbCarHLane();
        nextHCar = (int)(prob);
        hInc = nextHCar;   
    }

    /**
     * Asks and accept user input to set the probability of car entering
     * in the vertical street
     */
    public void setProbVerLaneCar(){
        boolean choice = false;
        int lowerLimit = 0;
        int upperLimit = 1;
        do {
            String userChoice = GetUserInput.getUserChoice("Enter number of probable cars in V-Lane : ");
            double userChoiceInt = Double.valueOf(userChoice.trim()).doubleValue();

            if (userChoiceInt > upperLimit || userChoiceInt < lowerLimit) {
               System.out.println("Error in entering probable number");
               System.out.println("Please enter number either 0 or 1. ");
            }
            else { //if user enter the correct input
                pm.setProbCarVLane(userChoiceInt);
                //let user set the number
                choice = true;
            }
        }while (choice != true);
        simVCycle = 1;
        double prob = 1.0/showProbCarVLane();
        nextVCar = (int)(prob);
        vInc = nextVCar;
    }

    /**
     * Creates new horizontal car array object and sets its position on the
     * Grid
     */
    public void createHCar(){
        horCarArray[hcounter] = new Car();
        horCarArray[hcounter].setNextHorCar(showHorLanes());
        cell.buildHCar(horCarArray[hcounter].getRPos(), horCarArray[hcounter].getCPos());
        hcounter++;
        if (hcounter == 99) {
            hcounter = 0;
            hReset = true;
        }
    }

    /**
     * Creates new vertical car array object and sets its position on the
     * Grid
     */
    public void createVCar(){
        verCarArray[vcounter] = new Car();
        verCarArray[vcounter].setNextVerCar(showVerLanes());
        cell.buildVCar(verCarArray[vcounter].getRPos(),verCarArray[vcounter].getCPos());
        vcounter++;
        if (vcounter == 99) {
            vcounter = 0;
            vReset = true;
        }
        
    }

    /**
     * Performs the traffic simulation
     *
     * @param number of simulation cycle
     * @param probability of horizontal car
     * @param probability of vertical car
     */
    public void runSim(int noOfCycle, double probH, double probV){
        int i = 0;
        int hcount = hcounter;
        int vcount = vcounter;
        if (hReset == true) hcount = SIZE - 1;
        if (vReset == true) vcount = SIZE - 1;
        if (noOfCycle == 0 || start != true){
            cell = new Grid(pm);           
            cell.buildVerticalBorder(showVerLanes());
            cell.buildHorizontalBorder(showHorLanes());
            cell.buildHorizontalStreet(showHorLanes());
            cell.buildVerticalStreet(showVerLanes());
            //cell.createBlock();
            cell.buildTSpace();
            cell.buildTrafficLight(tcounter);
            if (simHCycle == nextHCar){
                horCarArray[hcounter] = new Car();
                horCarArray[hcounter].setHorCar(showHorLanes());
                cell.buildHCar(horCarArray[hcounter].getRPos(), horCarArray[hcounter].getCPos());
                nextHCar = nextHCar + hInc;
            }
            if (simVCycle == nextVCar){
                verCarArray[vcounter] = new Car();
                verCarArray[vcounter].setVerCar(showVerLanes());
                cell.buildVCar(verCarArray[vcounter].getRPos(),verCarArray[vcounter].getCPos());
                nextVCar = nextVCar + vInc;
            }
            cell.show();
            tcounter++;
            hcounter++;
            vcounter++;
            simHCycle++;
            simVCycle++;
            i++;
        }
       
        int middleH = cell.getMidH(showVerLanes());
        int middleV = cell.getMidV(showHorLanes());
        int hBorderUp = middleV - showHorLanes() - 3;
        int vBorderLeft = middleH + showVerLanes() + 1;
        while (i<noOfCycle){
           if(start != true) start = true;
           cell.buildTrafficLight(tcounter);
           if (probH != 0) {
               if (simHCycle == nextHCar){
                createHCar();
                nextHCar = nextHCar+hInc;
               }
                for (int j = 0; j<=hcount;j++){
                    if (horCarArray[j] != null){
                        int row = horCarArray[j].getRPos();
                        int col = horCarArray[j].moveHCar();
                        if (cell.checkHTL()!='G'){
                            if (col == middleH-1) horCarArray[j].stopHCar();
                            else
                                if (cell.gridValue(row, col) != ' '){
                                    if (cell.gridValue(row+1, col) == ' ' && row+1 < middleV+2){
                                        cell.deleteCar(row, col-1);
                                        row++;
                                        horCarArray[j].changeLaneHCar(row);
                                        cell.overtakeCar(row, col);
                                    }
                                    else if(cell.gridValue(row - 1, col) == ' ' && row-1 > hBorderUp)
                                    {
                                        cell.deleteCar(row, col-1);
                                        row--;
                                        horCarArray[j].changeLaneHCar(row);
                                        cell.overtakeCar(row, col);
                                    }
                                    else
                                        horCarArray[j].stopHCar();
                                }
                                else cell.moveHorCar(row , col);

                        }

                        else {
                            if (cell.gridValue(row, col) == ' ')cell.moveHorCar(row , col);
                            else 
                                if (cell.gridValue(row, col) != ' '){
                                    if (cell.gridValue(row+1, col) == ' ' && row+1 < middleV+2){
                                        cell.deleteCar(row, col-1);
                                        row++;
                                        horCarArray[j].changeLaneHCar(row);
                                        cell.overtakeCar(row, col);
                                    }
                                    else if(cell.gridValue(row - 1, col) == ' ' && row-1 > hBorderUp)
                                    {
                                        cell.deleteCar(row, col-1);
                                        row--;
                                        horCarArray[j].changeLaneHCar(row);
                                        cell.overtakeCar(row, col);
                                    }
                                    else
                                        horCarArray[j].stopHCar();
                            }
                          }
                        if (horCarArray[j].getMoveHCar() == pm.getGridSize()){
                            cell.deleteCar(row, col);
                            horCarArray[j] = null;
                        }
                    }
                }
            }
           if (probV != 0){
               if(simVCycle == nextVCar){
                 createVCar();
                 nextVCar = nextVCar+vInc;
               }
            for (int k = 0; k<=vcount;k++){
                    if (verCarArray[k] != null){
                        int vrow = verCarArray[k].moveVCar();
                        int vcol = verCarArray[k].getCPos();
                        if (cell.checkVTL()!='G'){
                            if (vrow == middleV+1) verCarArray[k].stopVCar();
                            else
                                if (cell.gridValue(vrow, vcol) != ' '){
                                    if (cell.gridValue(vrow, vcol-1) == ' ' && vcol-1 > middleH-2){
                                        cell.deleteCar(vrow+1, vcol);
                                        vcol--;
                                        verCarArray[k].changeLaneVCar(vcol);
                                        cell.overtakeCar(vrow, vcol);
                                    }
                                    else if(cell.gridValue(vrow, vcol+1) == ' ' && vcol+1 < vBorderLeft)
                                    {
                                        cell.deleteCar(vrow+1, vcol);
                                        vcol++;
                                        verCarArray[k].changeLaneVCar(vcol);
                                        cell.overtakeCar(vrow, vcol);
                                    }
                                    else
                                        verCarArray[k].stopVCar();
                                }
                            else cell.moveVerCar(vrow , vcol);

                        }
                        else{
                            if (cell.gridValue(vrow, vcol) == ' ')cell.moveVerCar(vrow , vcol);
                            else 
                                if (cell.gridValue(vrow, vcol) != ' '){
                                    if (cell.gridValue(vrow, vcol-1) == ' ' && vcol-1 > middleH-2){
                                        cell.deleteCar(vrow+1, vcol);
                                        vcol--;
                                        verCarArray[k].changeLaneVCar(vcol);
                                        cell.overtakeCar(vrow, vcol);
                                    }
                                    else if(cell.gridValue(vrow, vcol+1) == ' '  && vcol+1 < vBorderLeft)
                                    {
                                        cell.deleteCar(vrow+1, vcol);
                                        vcol++;
                                        verCarArray[k].changeLaneVCar(vcol);
                                        cell.overtakeCar(vrow, vcol);
                                    }
                                    else
                                        verCarArray[k].stopVCar();
                                }
                        }
                        if (verCarArray[k].getMoveVCar() == -1){
                            cell.deleteCar(vrow, vcol);
                            verCarArray[k] = null;
                        }
                    }
                }
            }
            cell.show();
            i++;
            tcounter++;
            if (tcounter == 6){
                tcounter = 1;           
            }
        simHCycle++;
        simVCycle++;
        }
        System.out.println(hcounter);
        System.out.println(simHCycle);
        System.out.println(nextHCar);
    }

    /**
     * Returns the number of horizontal lane
     *
     * @return int
     */
    public int showHorLanes() {
        return pm.getHorLanes();
    }

    /**
     * Returns the number of vertical lane
     *
     * @return int
     */
    public int showVerLanes() {
        return pm.getVerLanes();
    }

    /**
     * Returns the probability of car entering in horizontal street
     *
     * @return double
     */
    public double showProbCarHLane() {
        return pm.getProbCarHLane();
    }

    /**
     * Returns the probability of car entering in vertical street
     *
     * @return double
     */
     public double showProbCarVLane() {
        return pm.getProbCarVLane();
    }
}